import { isValid, Node, Widget } from 'cc';
import { app } from '../App';
import { Logger } from '../common/log/Logger';
import { injectable, InjectableNode } from '../inject';
import UIDelegateComp from './component/UIDelegateComp';
import { UICallbacks, ViewConfig, ViewParams } from './ViewDefine';

@injectable('UILayer')
export default class UILayer extends InjectableNode {

    protected _uiMap: Map<string, ViewParams> = new Map<string, ViewParams>();

    constructor(name: string) {
        super(name);

        var widget: Widget = this.addComponent(Widget);
        widget.isAlignLeft = true;
        widget.isAlignRight = true;
        widget.isAlignBottom = true;
        widget.isAlignTop = true;
        widget.left = 0;
        widget.right = 0;
        widget.bottom = 0;
        widget.top = 0;
        widget.alignMode = 2;
        widget.enabled = true;
    }


    /** 构造一个唯一标识UUID */
    protected getUuid(prefabPath: string): string {
        var uuid = `${this.name}_${prefabPath}`;
        return uuid.replace(/\//g, "_");
    }

    openView(viewConf: ViewConfig, payload?: any, callbacks?: UICallbacks): string {
        var uuid = this.getUuid(viewConf.prefab);

        var vp: ViewParams = this._uiMap.get(uuid);

        if (vp && vp.valid) {
            Logger.warn(`路径为【${viewConf.prefab}】的预制重复加载`);
            return;
        }

        if (vp == null) {
            vp = new ViewParams();
            vp.uuid = uuid;
            vp.config = viewConf;
            vp.valid = false;

            this._uiMap.set(vp.uuid, vp);
        }

        /** reset payload and callbacks */
        vp.payload = payload;
        vp.callbacks = callbacks;

        /** add node */
        if (vp.node) {
            this.addUI(vp);
        } else {

            app.ui.createUI(vp.config.prefab, (node: Node) => {
                vp.node = node;
                let comp: UIDelegateComp = node.addComponent(UIDelegateComp);
                comp.viewParams = vp;
                this.addUI(vp);
            });
        }

        return uuid;
    }

    protected addUI(vp: ViewParams) {
        vp.valid = true;
        let ui: Node | null = vp!.node;
        ui.parent = this;

        let comp: UIDelegateComp | null = ui.getComponent(UIDelegateComp);
        comp!.add();

        return ui;
    }

    /**
     * 通过uuid删除，uimap也会删除
     * @param uuid 
     * @param isDestroy 
     */
    removeByUuid(uuid: string, isDestroy: boolean): void {
        var vp = this._uiMap.get(uuid);

        if (vp) {
            if (isDestroy) {
                this._uiMap.delete(uuid);
            }

            var ui = vp.node;
            var comp = ui?.getComponent(UIDelegateComp);
            comp.remove(isDestroy);

            vp.valid = false;
        }
    }

    /**
     * 根据预制节点路径删除，uimap也会删除
     * @param prefabPath 
     * @param isDestroy 
     */
    remove(prefabPath: string, isDestroy: boolean): void {
        let allComps = this.__comps();

        for (let i = 0; i < allComps.length; i++) {
            let vp = allComps[i].viewParams;

            if (vp.config.prefab === prefabPath) {
                if (isDestroy) {
                    this._uiMap.delete(vp.uuid);
                }

                allComps[i].remove(isDestroy);

                vp.valid = false;
            }
        }
    }

    has(prefabPathOrUuid: string): boolean {
        let allComps = this.__comps();
        for (let comp of allComps) {
            if (comp.viewParams!.uuid == prefabPathOrUuid
                || comp.viewParams!.config.prefab == prefabPathOrUuid) {
                return true;
            }
        }

        return false;
    }

    /**
     * 通过uuid获取节点
     * @param uuid 
     * @returns 
     */
    getNodeByUuid(uuid: string): Node | null {
        let allComps = this.__comps();
        for (let comp of allComps) {
            if (comp.viewParams && comp.viewParams.uuid === uuid)
                return comp.node;
        }

        return null;
    }

    size(): number {
        return this.children.length;
    }

    clear(isDestroy: boolean): void {
        this._uiMap.forEach((value: ViewParams, key: string) => {
            this.removeByUuid(value.uuid, isDestroy);
            value.valid = false;
        });

        this._uiMap.clear();
    }

    protected __comps(): Array<UIDelegateComp> {
        let ret: Array<UIDelegateComp> = [];

        let children = this.children;

        for (let i = 0; i < children.length; i++) {
            let comp = children[i].getComponent(UIDelegateComp);
            if (comp && comp.viewParams && comp.viewParams.valid && isValid(comp)) {
                ret.push(comp);
            }
        }

        return ret;
    }
}